import { defineComponent, computed, getCurrentInstance, onBeforeUnmount, provide, reactive } from "vue";
import "./vue-flow-editor.scss";
import { useCanvasProps, useEditorCommander, useEditorStyles, VueFlowEditorProvider } from "@/editor/editor";
import { formatNodeModel, suffixSize } from "@/utils/utils";

export default {
  name: "vue-flow-editor",
  props: {
    data: { type: Object }, // 渲染的数据
    grid: { type: Boolean, default: true }, // 是否需要网格
    miniMap: { type: Boolean, default: false }, // 是否需要缩略图
    disabledDragEdge: { type: Boolean }, // 禁用拖拽连线功能
    disabledUndo: { type: Boolean }, // 禁用撤销以及重做功能
    editorTitle: { type: String }, // 编辑器标题

    height: { type: [String, Number], default: "100%" }, // 画布高度
    toolbarHeight: { type: [String, Number], default: "56" }, // 顶部工具栏高度
    menuWidth: { type: [String, Number], default: "250" }, // 左侧菜单栏高度
    modelWidth: { type: [String, Number], default: "500px" }, // model 弹框的宽度

    onRef: { type: Function }, // 获取引用函数
    toolbarButtonHandler: { type: Function }, // 工具栏按钮格式化函数
    loading: { type: Boolean }, // 是否开启编辑器的loading状态

    multipleSelect: { type: Boolean, default: true }, // 是否可以多选

    beforeDelete: { type: Function }, // 删除前校验
    afterDelete: { type: Function }, // 删除后动作
    beforeAdd: { type: Function }, // 添加前校验
    afterAdd: { type: Function }, // 添加后动作

    activityConfig: { type: Object }, // 注册活动节点
  },
  setup(props, context) {
    const styles = useEditorStyles(props);
    const canvasProps = useCanvasProps(props);

    const modelBodyStyle = computed(() => ({
      width: suffixSize(props.modelWidth),
    }));

    const editorState = reactive({
      graph: null as any, // graph 对象，canvas组件挂载初始化完毕会给这个属性赋值
      canvasProps, // 传给canvas组件的属性，同时可以修改
      props, // 当前组件接收得到的属性，供子组件通过inject获取
      canvasKey: 0, // canvas组件的key，以刷新canvas组件
      showModel: false, // 详情对话框是否显示
      showPreview: false, // 预览对话框显示
      data: null,
      refreshCanvas: () => {
        // 刷新canvas组件
        editorState.canvasKey++;
      },
      setGraph: (graph) => {
        editorState.graph = graph;
        commander.init(graph);

        graph.on("node:dblclick", (e) => {
          context.emit("dblclick-node", e);
        });
        graph.on("edge:dblclick", (e) => {
          context.emit("dblclick-edge", e);
        });
        graph.on("select-change", (e) => {
          context.emit("select-change", e);
        });
      },
    });
    const commander = useEditorCommander(editorState);

    const provideContext = {
      props,
      editorState,
      commander,
      openModel: () => {
        editorState.showModel = true;
      },
      closeModel: () => {
        editorState.showModel = false;
      },
      updateModel: (model) => {
        formatNodeModel(model, props.activityConfig);
        commander.commands.update(model);
      },
      openPreview: () => {
        editorState.data = editorState.graph.save();
        editorState.showPreview = true;
      },
      read: (data) => {
        if (!!editorState.graph) {
          editorState.graph.read(data);
        } else {
          console.warn("graph is not initialized");
        }
      },
    };
    provide(VueFlowEditorProvider, provideContext);

    if (!!props.onRef) {
      props.onRef(provideContext);
    }

    const ctx = getCurrentInstance();
    Object.assign(ctx, provideContext);

    onBeforeUnmount(() => {
      commander.destroy();
      if (!!props.onRef) {
        props.onRef(null);
      }
    });

    return () => (
      <div class="vue-flow-editor" style={styles.value.root} v-loading={props.loading}>
        <div class="vue-flow-editor-left" style={styles.value.left}>
          <vue-flow-editor-menu>{!!context.slots.menu && context.slots.menu()}</vue-flow-editor-menu>
        </div>
        <div class="vue-flow-editor-right">
          <vue-flow-editor-toolbar
            style={styles.value.toolbar}
            canvasProps={canvasProps}
            toolbarButtonHandler={props.toolbarButtonHandler}
          >
            {!!context.slots.toolbar && context.slots.toolbar()}
          </vue-flow-editor-toolbar>
          <vue-flow-editor-canvas
            data={canvasProps.data}
            grid={canvasProps.grid}
            miniMap={canvasProps.miniMap}
            key={String(editorState.canvasKey) + String(props.multipleSelect) + String(props.disabledDragEdge)}
          />
        </div>
        <transition name="vue-flow-editor-transition">
          <div class="vue-flow-editor-model" v-show={editorState.showModel}>
            <div class="vue-flow-editor-model-body" style={modelBodyStyle.value}>
              <div class="vue-flow-editor-model-head" style={styles.value.toolbar}>
                <i class="el-icon-close" onClick={provideContext.closeModel} />
              </div>
              <div class="vue-flow-editor-model-content">{!!context.slots.model && context.slots.model()}</div>
              {!!context.slots.foot && <div class="vue-flow-editor-model-foot">{context.slots.foot()}</div>}
            </div>
          </div>
        </transition>

        <vue-flow-editor-preview
          value={editorState.showPreview}
          onInput={(val) => (editorState.showPreview = val)}
          data={editorState.data}
        />
      </div>
    );
  },
};
